package org.icosagon.core.magic;

/*
 * TODO - Add durration to this class.
 * TODO - Add descriptors to this class - The descriptors are acid,
 * air, chaotic, cold, darkness, death, earth, electricity, evil, fear, fire, force,
 * good, language-dependent, lawful, light, mind-affecting, sonic, and water.
 */

import java.util.List;
import java.util.Vector;
import javax.xml.bind.annotation.XmlElement;
import org.icosagon.core.Definable;
import org.icosagon.core.InvalidNumberException;
import org.icosagon.utils.Time;
import org.icosagon.core.math.Equation;

/**
 *
 * @author Daniel Owens
 */
public class Spell extends Definable {
    /**
     * These are the different variables for a spell's area.
     */
    public static final String CONE = "CONE", CYLINDER="CYLINDER", LINE="LINE", SPHERE="SPHERE";

    /** This field is used to specify either school(arcane) or domain(divine) of a spell. Can be null*/
    private String type = null;
    /** This field is specifies the subschool(arcane) or subdomain(divine) of a spell. Can be null. */
    private String subtype = null;
    private String area = "";
    private int level = 0;
    private boolean divine = false;
    private boolean resistance = true;
    private Vector<Component> components = new Vector<Component>();
    private Vector<Effect> effects = new Vector<Effect>();
    private Equation range = null;
    private Time time = new Time("ROUND");
    private SavingThrow saves = null;

    public Spell(){}
    public Spell(String name) {
        this.setName(name);
    }

    /**
     * Sets the school if the spell is arcane or sets the domain if the spell is divine.
     * @param school
     */
    public void setType(String school) {
        this.type = school.trim();
    }

    /**
     * Returns the school if the spell is arcane or gets the domain if the spell is divine.
     * If the <code>String</code> is empty <code>null</code> will be returned.
     * @return
     */
    @XmlElement(name="type")
    public String getType() {
        if(this.type.equals(""))
            return null;
        return this.type;
    }

    /**
     * Sets the subschool if the spell is arcane or sets the subdomain if the spell is divine.
     * @param school
     */
    public void setSubtype(String sub) {
        this.subtype = sub.trim();
    }

    /**
     * Returns the subschool if the spell is arcane or gets the subdomain if the spell is divine.
     * If the <code>String</code> is empty <code>null</code> will be returned.
     * @return
     */
    @XmlElement
    public String getSubtype() {
        if(this.type.equals(""))
            return null;
        return this.subtype;
    }

    public void setLevel(int lvl) throws InvalidNumberException {
        if(lvl < 0)
            throw new InvalidNumberException("Spell level cannot be less than 0");
        this.level = lvl;
    }

    @XmlElement
    public int getLevel() {
        return this.level;
    }

    public boolean isArcane() {
        boolean value = this.divine ? false : true;
        return value;
    }

    public boolean isDivine() {
        return this.divine;
    }

    public void addComponent(Component component) {
        this.components.add(component);
    }

    public void removeComponent(Component component) {
        this.components.remove(component);
    }


    public Vector<Component> getComponents() {
        return new Vector(this.components);
    }

    public void setCastingTime(Time time) throws InvalidNumberException {
	this.time = time;
    }

    public Time getCastingTime() {
	return this.time;
    }

    public void setRange(Equation reach) throws InvalidNumberException {
        this.range = reach;
    }

    public Equation getRange() {
        return this.range;
    }

    public void setArea(String area) {
        this.area = area.trim();
    }

    public String getArea() {
        return this.area;
    }

    public void setSavingThrow(SavingThrow save) {
        this.saves = save;
    }

    public SavingThrow getSavingThow() {
        return this.saves;
    }

    public void putEffect(Effect effect) {
        this.effects.add(effect);
    }

    public void removeEffect(Effect effect) {
        this.effects.remove(effect);
    }

    public Vector<Effect> getEffects() {
        return this.effects;
    }

    public void setResistance(boolean value) {
        this.resistance = value;
    }

    public boolean getResistance() {
        return this.resistance;
    }

    public void setDivine(boolean value) {
	this.divine = value;
    }
}